
#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using MUSA;
#endregion


namespace MUSA
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class MUSA : Microsoft.Xna.Framework.Game
    {
        #region Variables

        public static GraphicsDeviceManager mGraphicsManager;
        public static GraphicsDevice mGraphicsDevice;
        public static ContentManager mContentManager;

        public static GameTime globalGameTime;

        public static List<Object> mObjectList;
        public static List<Plane> mBoundList;

        //group leader list
        private static List<GroupLeader> mGroupLeaderList;

        private static ExplosionManager eman;

        /*
         * The camera supplies the view and projection matrix
         * information for drawing the various models
         */
        public static Camera mCamera;                //camera

        Terrain mTerrain;

        Text tankFeedback;

        #endregion

        #region Constructor

        /// <summary>
        /// Musa Constructor
        /// </summary>
        public MUSA()
        {
            mGraphicsManager = new GraphicsDeviceManager(this);
            mContentManager = new ContentManager(Services);
        }

        #endregion

        /// <summary>
        /// Methods Implemented by XNA Framework
        /// </summary>
        #region XNA Framework

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            
            base.Initialize();

        }

        /// <summary>
        /// Load your graphics content.  If loadAllContent is true, you should
        /// load content from both ResourceManagementMode pools.  Otherwise, just
        /// load ResourceManagementMode.Manual content.
        /// </summary>
        /// <param name="loadAllContent">Which type of content to load.</param>
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            mGraphicsDevice = mGraphicsManager.GraphicsDevice;

            //settings
            mGraphicsManager.GraphicsDevice.RenderState.CullMode = CullMode.None;       // Turn off culling so the back side of the triangles can be seen.

            //initialize camera
            mCamera = new Camera(new Vector3(0, 0, 50), Vector3.Zero);

            //initialize lists
            mObjectList = new List<Object>();           //list of tanks(not really objects)

            mBoundList = new List<Plane>(); ;           //map boundaries

            mGroupLeaderList = new List<GroupLeader>(); //groups

            eman = new ExplosionManager();

            if (loadAllContent)
            {
                //Instantiate Terrain
                //========================================
                mTerrain = new Terrain(this);

                //Instantiate Text
                //========================================
                tankFeedback = new Text(true);
                tankFeedback.LoadFont();

                //Instantiate Tanks
                //========================================
                List<Tank> Team1TankList = new List<Tank>();
                List<Tank> Team2TankList = new List<Tank>();

                //Create Tank 1
                Vector3 nPosition = new Vector3(-20 , -8 , 0);
                Vector3 nDirection = new Vector3(1.0f , 0 , 0);

                Tank nTank = new Tank(this, nPosition, nDirection, TeamColor.RED);
                mObjectList.Add(nTank);
                Team1TankList.Add(nTank);

                //Create Tank 2
                nPosition = new Vector3(-20, -4, 0);

                Tank nTank2 = new Tank(this, nPosition, nDirection, TeamColor.RED);
                mObjectList.Add(nTank2);
                Team1TankList.Add(nTank2);

                //Create Tank 3
                nPosition = new Vector3(-20, 0, 0);

                Tank nTank3 = new Tank(this, nPosition, nDirection, TeamColor.RED, TankState.Offense);
                mObjectList.Add(nTank3);
                Team1TankList.Add(nTank3);

                //Create Tank 4
                nPosition = new Vector3(-20, 4, 0);

                Tank nTank4 = new Tank(this, nPosition, nDirection, TeamColor.RED, TankState.Offense);
                mObjectList.Add(nTank4);
                Team1TankList.Add(nTank4);

                

                //Create Tank 5
                nPosition = new Vector3(20, -8, 0);

                nDirection = new Vector3(-1.0f, 0, 0);
                Tank nTank5 = new Tank(this, nPosition, nDirection, TeamColor.BLUE);

                mObjectList.Add(nTank5);
                Team2TankList.Add(nTank5);

                //Create Tank 6
                nPosition = new Vector3(20, -4, 0);
                Tank nTank6 = new Tank(this, nPosition, nDirection, TeamColor.BLUE);

                 mObjectList.Add(nTank6);
                Team2TankList.Add(nTank6);


                //Create Tank 7
                nPosition = new Vector3(20, 0, 0);
                Tank nTank7 = new Tank(this, nPosition, nDirection, TeamColor.BLUE, TankState.Offense);

                 mObjectList.Add(nTank7);
                Team2TankList.Add(nTank7);

                
                //Create Tank 8
                nPosition = new Vector3(20, 4, 0);
                Tank nTank8 = new Tank(this, nPosition, nDirection, TeamColor.BLUE, TankState.Offense);

                 mObjectList.Add(nTank8);
                Team2TankList.Add(nTank8);

                //Instantiate Group Leader
                //========================================

                GroupLeader team1 = new GroupLeader(this, new Vector3(5, 0, 0), Team1TankList.ToArray(), TeamColor.RED);
                GroupLeader team2 = new GroupLeader(this, new Vector3(-5, 0, 0), Team2TankList.ToArray(), TeamColor.BLUE);

                //load groups
                mGroupLeaderList.Add(team1);
                mGroupLeaderList.Add(team2);

                //create bounding volume
                Plane p = new Plane(new Vector3(-1, 0, 0), 35);
                mBoundList.Add(p);

                p = new Plane(new Vector3(1, 0, 0), 35);
                mBoundList.Add(p);

                p = new Plane(new Vector3(0, 1, 0), 35);
                mBoundList.Add(p);

                p = new Plane(new Vector3(0, -1, 0), 35);
                mBoundList.Add(p);
            }

            // TODO: Load any ResourceManagementMode.Manual content
        }

        /// <summary>
        /// Unload your graphics content.  If unloadAllContent is true, you should
        /// unload content from both ResourceManagementMode pools.  Otherwise, just
        /// unload ResourceManagementMode.Manual content.  Manual content will get
        /// Disposed by the GraphicsDevice during a Reset.
        /// </summary>
        /// <param name="unloadAllContent">Which type of content to unload.</param>
        protected override void UnloadGraphicsContent(bool unloadAllContent)
        {
            if (unloadAllContent == true)
            {
                mContentManager.Unload();
            }
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime  gameTime)
        {
            //check for ESCAPE
            if(Keyboard.GetState().IsKeyDown(Keys.Escape))
            {
                //exit MUSA
                this.Exit();
            }

            //base update
            base.Update(gameTime);

            globalGameTime = gameTime;

            List<Object> cullList;
            cullList = new List<Object>();

            foreach (Object o in mObjectList)
            {
                /*
                 * note: verify that the following if statement filter's out
                 * non tank objects, I wasn't really sure if it would work
                 * from what I quickly gleamed from the documentation
                 */

                //this needs to be moved somewhere else
                ProjectileManager.checkCollision((Tank)o);

                //print out tank information
                if (o is Tank)
                {
                    Tank t = (Tank)o;

                    tankFeedback.updateTankStat(o.Position , t.CurrentState , t.TankID , t.Team , 50);

                    if(t.Dead)
                    {
                        cullList.Add(o);
                        tankFeedback.RemoveTank(t.TankID);
                        continue;
                    }
                }

                foreach (GroupLeader item in mGroupLeaderList)
                {
                    item.Update(gameTime);
                }

                //update tank
                o.Update(gameTime);
            }

            foreach(Object o in cullList)
            {
                eman.AddExplosion(o.Position);

                mObjectList.Remove(o);
            }

            //hoachange
            foreach (GroupLeader item in mGroupLeaderList)
            {
                item.Update(gameTime);
            }

            ProjectileManager.Update(gameTime);
            eman.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
            
            //clear screen
            mGraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, new Vector4(0, 0, 0, 255), 1.0f, 0);

            // Turn off culling so the back side of the triangles can be seen.
            mGraphicsManager.GraphicsDevice.RenderState.CullMode = CullMode.None;

            foreach (Object item in mObjectList)
            {
                item.Draw(gameTime);
            }

            ProjectileManager.Draw(gameTime);

            //mTerrain.Draw(gameTime);

            eman.Draw(gameTime);

            tankFeedback.Draw();
        }

        #endregion
    }
}